import requests
import json

base_url = "http://localhost:8080/api"
bookshelf_url = f"{base_url}/bookshelf"
users_url = f"{base_url}/users"


# 首先登入用户
def login_user(username, password):
    """用户登录并返回token"""
    login_data = {"username": username, "password": password}
    response = requests.post(
        f"{users_url}/login",
        json=login_data,
        headers={"Content-Type": "application/json"},
    )
    if response.status_code == 200:
        return response.json().get("token")
    else:
        print(f"登录失败: {response.json()}")
        return None


def register_user(username, password):
    """用户注册"""
    register_data = {"username": username, "password": password}
    response = requests.post(
        f"{users_url}/register",
        json=register_data,
        headers={"Content-Type": "application/json"},
    )
    return response.status_code == 200


def test_bookshelf_info():
    """测试获取书架管理接口信息"""
    print("=== 测试获取书架管理接口信息 ===")

    try:
        response = requests.get(f"{bookshelf_url}/")

        print(f"状态码: {response.status_code}")
        print(f"响应内容: {response.json()}")

        if response.status_code == 200:
            print("✅ 获取书架接口信息成功")
            return True
        else:
            print("❌ 获取书架接口信息失败")
            return False

    except Exception as e:
        print(f"❌ 获取书架接口信息请求异常: {e}")
        return False


def test_add_book_to_bookshelf(token, book_id=1):
    """测试添加图书到书架"""
    print(f"\n=== 测试添加图书到书架 (book_id: {book_id}) ===")

    if not token:
        print("❌ 没有有效的token，跳过测试")
        return False

    headers = {
        "Authorization": f"Bearer {token}",
        "Content-Type": "application/json",
    }

    data = {"book_id": book_id}

    try:
        response = requests.post(f"{bookshelf_url}/add", json=data, headers=headers)

        print(f"状态码: {response.status_code}")
        print(f"响应内容: {response.json()}")

        if response.status_code == 200:
            print("✅ 添加图书到书架成功")
            return True
        elif response.status_code == 400 and "已存在" in response.json().get(
            "message", ""
        ):
            print("✅ 图书已在书架中（预期行为）")
            return True
        else:
            print("❌ 添加图书到书架失败")
            return False

    except Exception as e:
        print(f"❌ 添加图书到书架请求异常: {e}")
        return False


def test_add_duplicate_book(token, book_id=1):
    """测试重复添加同一本图书"""
    print(f"\n=== 测试重复添加图书 (book_id: {book_id}) ===")

    if not token:
        print("❌ 没有有效的token，跳过测试")
        return False

    headers = {
        "Authorization": f"Bearer {token}",
        "Content-Type": "application/json",
    }

    data = {"book_id": book_id}

    try:
        response = requests.post(f"{bookshelf_url}/add", json=data, headers=headers)

        print(f"状态码: {response.status_code}")
        print(f"响应内容: {response.json()}")

        if response.status_code == 400 and "已存在" in response.json().get(
            "message", ""
        ):
            print("✅ 重复添加验证成功")
            return True
        else:
            print("❌ 重复添加验证失败")
            return False

    except Exception as e:
        print(f"❌ 重复添加图书请求异常: {e}")
        return False


def test_get_bookshelf_list(token, page=1, limit=10):
    """测试获取书架列表"""
    print(f"\n=== 测试获取书架列表 (page: {page}, limit: {limit}) ===")

    if not token:
        print("❌ 没有有效的token，跳过测试")
        return False

    headers = {
        "Authorization": f"Bearer {token}",
        "Content-Type": "application/json",
    }

    try:
        response = requests.get(
            f"{bookshelf_url}/list?page={page}&limit={limit}", headers=headers
        )

        print(f"状态码: {response.status_code}")
        response_data = response.json()
        print(f"响应内容: {json.dumps(response_data, ensure_ascii=False, indent=2)}")

        if response.status_code == 200:
            print("✅ 获取书架列表成功")
            print(f"总数: {response_data.get('total', 0)}")
            print(f"当前页图书数量: {len(response_data.get('books_list', []))}")
            return True
        else:
            print("❌ 获取书架列表失败")
            return False

    except Exception as e:
        print(f"❌ 获取书架列表请求异常: {e}")
        return False


def test_remove_book_from_bookshelf(token, book_id=1):
    """测试从书架移除图书"""
    print(f"\n=== 测试从书架移除图书 (book_id: {book_id}) ===")

    if not token:
        print("❌ 没有有效的token，跳过测试")
        return False

    headers = {
        "Authorization": f"Bearer {token}",
        "Content-Type": "application/json",
    }

    try:
        response = requests.delete(
            f"{bookshelf_url}/remove?book_id={book_id}", headers=headers
        )

        print(f"状态码: {response.status_code}")
        print(f"响应内容: {response.json()}")

        if response.status_code == 200:
            print("✅ 从书架移除图书成功")
            return True
        elif response.status_code == 400 and "不在书架中" in response.json().get(
            "message", ""
        ):
            print("✅ 图书不在书架中（预期行为）")
            return True
        else:
            print("❌ 从书架移除图书失败")
            return False

    except Exception as e:
        print(f"❌ 从书架移除图书请求异常: {e}")
        return False


def test_remove_nonexistent_book(token, book_id=999):
    """测试移除不存在的图书"""
    print(f"\n=== 测试移除不存在的图书 (book_id: {book_id}) ===")

    if not token:
        print("❌ 没有有效的token，跳过测试")
        return False

    headers = {
        "Authorization": f"Bearer {token}",
        "Content-Type": "application/json",
    }

    try:
        response = requests.delete(
            f"{bookshelf_url}/remove?book_id={book_id}", headers=headers
        )

        print(f"状态码: {response.status_code}")
        print(f"响应内容: {response.json()}")

        if response.status_code == 400 and "不在书架中" in response.json().get(
            "message", ""
        ):
            print("✅ 移除不存在图书验证成功")
            return True
        else:
            print("❌ 移除不存在图书验证失败")
            return False

    except Exception as e:
        print(f"❌ 移除不存在图书请求异常: {e}")
        return False


def test_unauthorized_access():
    """测试未授权访问"""
    print("\n=== 测试未授权访问 ===")

    try:
        # 测试没有token的情况
        data = {"book_id": 1}
        headers = {"Content-Type": "application/json"}  # 添加Content-Type
        response = requests.post(f"{bookshelf_url}/add", json=data, headers=headers)
        print(f"无token访问 - 状态码: {response.status_code}")

        # 测试无效token的情况
        headers = {
            "Authorization": "Bearer invalid_token",
            "Content-Type": "application/json",
        }
        response = requests.post(f"{bookshelf_url}/add", json=data, headers=headers)
        print(f"无效token访问 - 状态码: {response.status_code}")

        if response.status_code == 401:
            print("✅ 未授权访问验证成功")
            return True
        else:
            print("❌ 未授权访问验证失败")
            return False

    except Exception as e:
        print(f"❌ 未授权访问测试异常: {e}")
        return False


def test_invalid_book_id(token):
    """测试无效的图书ID"""
    print("\n=== 测试无效的图书ID ===")

    if not token:
        print("❌ 没有有效的token，跳过测试")
        return False

    headers = {
        "Authorization": f"Bearer {token}",
        "Content-Type": "application/json",
    }

    try:
        # 测试缺少book_id参数
        data = {}  # 空的请求体
        response = requests.post(f"{bookshelf_url}/add", json=data, headers=headers)
        print(f"缺少book_id - 状态码: {response.status_code}")

        # 测试无效的book_id类型
        data = {"book_id": "invalid"}
        response = requests.post(f"{bookshelf_url}/add", json=data, headers=headers)
        print(f"无效book_id类型 - 状态码: {response.status_code}")

        if response.status_code == 422:  # FastAPI参数验证错误
            print("✅ 无效图书ID验证成功")
            return True
        else:
            print("❌ 无效图书ID验证失败")
            return False

    except Exception as e:
        print(f"❌ 无效图书ID测试异常: {e}")
        return False


def test_request_body_formats(token):
    """测试不同的请求体格式"""
    print("\n=== 测试不同的请求体格式 ===")

    if not token:
        print("❌ 没有有效的token，跳过测试")
        return False

    headers = {
        "Authorization": f"Bearer {token}",
        "Content-Type": "application/json",
    }

    try:
        # 测试正确的JSON格式
        data = {"book_id": 100}
        response = requests.post(f"{bookshelf_url}/add", json=data, headers=headers)
        print(f"正确JSON格式 - 状态码: {response.status_code}")

        # 测试错误的Content-Type
        headers_wrong = {
            "Authorization": f"Bearer {token}",
            "Content-Type": "application/x-www-form-urlencoded",
        }
        response = requests.post(
            f"{bookshelf_url}/add", data=data, headers=headers_wrong
        )
        print(f"错误Content-Type - 状态码: {response.status_code}")

        # 测试空请求体
        response = requests.post(f"{bookshelf_url}/add", headers=headers)
        print(f"空请求体 - 状态码: {response.status_code}")

        # 测试无效JSON
        headers_json = {
            "Authorization": f"Bearer {token}",
            "Content-Type": "application/json",
        }
        response = requests.post(
            f"{bookshelf_url}/add", data="invalid json", headers=headers_json
        )
        print(f"无效JSON - 状态码: {response.status_code}")

        print("✅ 请求体格式测试完成")
        return True

    except Exception as e:
        print(f"❌ 请求体格式测试异常: {e}")
        return False


def test_batch_add_books(token):
    """测试批量添加图书（通过多次调用）"""
    print("\n=== 测试批量添加图书 ===")

    if not token:
        print("❌ 没有有效的token，跳过测试")
        return False

    headers = {
        "Authorization": f"Bearer {token}",
        "Content-Type": "application/json",
    }

    book_ids = [10, 11, 12, 13, 14]
    success_count = 0

    try:
        for book_id in book_ids:
            data = {"book_id": book_id}
            response = requests.post(f"{bookshelf_url}/add", json=data, headers=headers)

            if response.status_code == 200:
                success_count += 1
                print(f"✅ 成功添加图书 {book_id}")
            elif response.status_code == 400 and "已存在" in response.json().get(
                "message", ""
            ):
                success_count += 1  # 已存在也算成功
                print(f"✅ 图书 {book_id} 已在书架中")
            else:
                print(f"❌ 添加图书 {book_id} 失败: {response.json()}")

        print(f"✅ 批量添加完成，成功: {success_count}/{len(book_ids)}")
        return success_count == len(book_ids)

    except Exception as e:
        print(f"❌ 批量添加图书异常: {e}")
        return False


def run_all_bookshelf_tests():
    """运行所有书架测试"""
    print("开始书架功能测试...")
    print("=" * 60)

    # 测试用户名（使用时间戳确保唯一性）
    import time

    username = f"bookshelf_test_user_{int(time.time())}"
    password = "123456"

    # 1. 注册测试用户
    print(f"注册测试用户: {username}")
    if not register_user(username, password):
        print("❌ 用户注册失败，测试终止")
        return

    # 2. 登录获取token
    print(f"登录测试用户: {username}")
    token = login_user(username, password)
    if not token:
        print("❌ 用户登录失败，测试终止")
        return

    print(f"✅ 获得token: {token[:20]}...")

    # 3. 测试获取书架接口信息
    test_bookshelf_info()

    # 4. 测试未授权访问
    test_unauthorized_access()  # 5. 测试无效参数
    test_invalid_book_id(token)

    # 5.1. 测试请求体格式
    test_request_body_formats(token)

    # 6. 测试添加图书到书架
    test_add_book_to_bookshelf(token, book_id=1)
    test_add_book_to_bookshelf(token, book_id=2)
    test_add_book_to_bookshelf(token, book_id=3)

    # 7. 测试重复添加
    test_add_duplicate_book(token, book_id=1)

    # 7.1. 测试批量添加
    test_batch_add_books(token)

    # 8. 测试获取书架列表
    test_get_bookshelf_list(token, page=1, limit=10)

    # 9. 测试分页
    test_get_bookshelf_list(token, page=1, limit=2)

    # 10. 测试移除图书
    test_remove_book_from_bookshelf(token, book_id=2)

    # 11. 测试移除不存在的图书
    test_remove_nonexistent_book(token, book_id=999)

    # 12. 再次获取书架列表验证移除效果
    test_get_bookshelf_list(token, page=1, limit=10)

    # 13. 测试移除剩余图书
    test_remove_book_from_bookshelf(token, book_id=1)
    test_remove_book_from_bookshelf(token, book_id=3)

    # 14. 测试空书架
    test_get_bookshelf_list(token, page=1, limit=10)

    # 15. 测试请求体格式
    test_request_body_formats(token)

    # 16. 测试批量添加图书
    test_batch_add_books(token)

    print("\n" + "=" * 60)
    print("书架功能测试完成")


if __name__ == "__main__":
    run_all_bookshelf_tests()
